package com.cdy.demo.java;

import org.springframework.cglib.reflect.FastClass;
import org.springframework.cglib.reflect.FastMethod;

import java.lang.reflect.Method;

/**
 * https://blog.csdn.net/jiangtao_st/article/details/19497685
 */
public class TestMethod {
    
    private static final int INT = 1;
    private static final String STRING = "name";
    private static final Object[] INTS = {1};
    private static final Object[] STRINGS = new String[]{STRING};
    
    private static final Bean BEAN = new Bean();
    
    private static final MethodBean METHOD = new MethodBean();
    private static final OptimizationMethodBean OPTIMIZATION_METHOD = new OptimizationMethodBean();
    private static final CglibMethod CGLIB_METHOD = new CglibMethod();
    
    private static final long LOOP = 1 * 10000 * 10000;
    
    // 测试main
    public static void main(String[] args) {
        // 直接调用
        test();
        // 反射调用
        testReflection();
        // 优化后反射调用
        testOptimizationReflection();
        // cglib反射调用
        testCglibReflection();
    }
    
    // 直接调用测试
    public static void test() {
        long start = System.currentTimeMillis();
        for (long i = 0; i < LOOP; i++) {
            BEAN.setId(new Integer(1));
            BEAN.setName("1");
        }
        long dur = System.currentTimeMillis() - start;
        System.out.println("直接调用测试:" + dur);
    }
    
    // 反射调用测试
    public static void testReflection() {
        long start = System.currentTimeMillis();
        for (long i = 0; i < LOOP; i++) {
            try {
                METHOD.setId.invoke(BEAN, new Object[]{1});
                METHOD.setName.invoke(BEAN, new Object[]{"1"});
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        long dur = System.currentTimeMillis() - start;
        System.out.println("反射调用测试:" + dur);
    }
    
    // 优化后反射调用测试
    public static void testOptimizationReflection() {
        long start = System.currentTimeMillis();
        for (long i = 0; i < LOOP; i++) {
            try {
                OPTIMIZATION_METHOD.setId.invoke(BEAN, new Object[]{1});
                OPTIMIZATION_METHOD.setName.invoke(BEAN, new Object[]{"1"});
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        long dur = System.currentTimeMillis() - start;
        System.out.println("优化后反射调用测试:" + dur);
    }
    
    // cglib反射调用测试
    public static void testCglibReflection() {
        long start = System.currentTimeMillis();
        for (long i = 0; i < LOOP; i++) {
            try {
                CGLIB_METHOD.cglibSetId.invoke(BEAN, new Object[]{1});
                CGLIB_METHOD.cglibSetName.invoke(BEAN, new Object[]{"1"});
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        long dur = System.currentTimeMillis() - start;
        System.out.println("cglib反射调用测试:" + dur);
    }
    
    /**
     * 测试的bean, 简单的int String类型
     */
    public static class Bean {
        private int id;
        private String name;
        
        public int getId() {
            return id;
        }
        
        public void setId(int id) {
            this.id = id;
        }
        
        public String getName() {
            return name;
        }
        
        public void setName(String name) {
            this.name = name;
        }
    }
    
    /**
     * 反射测试需要:Method bean
     */
    public static class MethodBean {
        
        public Method setId;
        public Method setName;
        
        {
            try {
                setId = Bean.class.getDeclaredMethod("setId", int.class);
                setName = Bean.class.getDeclaredMethod("setName", String.class);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    /**
     * 反射测试需要:优化后的Method bean
     */
    public static class OptimizationMethodBean extends MethodBean {
        {
            /** 所谓的优化 */
            setId.setAccessible(true);
            setName.setAccessible(true);
        }
    }
    
    /**
     * 反射测试需要,使用cglib的fast method
     */
    public static class CglibMethod extends MethodBean {
        public FastMethod cglibSetId;
        public FastMethod cglibSetName;
        private FastClass cglibBeanClass = FastClass.create(Bean.class);
        
        {
            cglibSetId = cglibBeanClass.getMethod(setId);
            cglibSetName = cglibBeanClass.getMethod(setName);
        }
    }
    
}